describe('ClearStack', function() {
  it('works in an integrationy way', function(done) {
    var clearStack = jasmineUnderTest.getClearStack(
      jasmineUnderTest.getGlobal()
    );

    clearStack(function() {
      done();
    });
  });

  it('uses setImmediate when available', function() {
    var setImmediate = jasmine
        .createSpy('setImmediate')
        .and.callFake(function(fn) {
          fn();
        }),
      global = { setImmediate: setImmediate },
      clearStack = jasmineUnderTest.getClearStack(global),
      called = false;

    clearStack(function() {
      called = true;
    });

    expect(called).toBe(true);
    expect(setImmediate).toHaveBeenCalled();
  });

  it('uses setTimeout instead of setImmediate every 10 calls to make sure we release the CPU', function() {
    var setImmediate = jasmine.createSpy('setImmediate'),
      setTimeout = jasmine.createSpy('setTimeout'),
      global = { setImmediate: setImmediate, setTimeout: setTimeout },
      clearStack = jasmineUnderTest.getClearStack(global);

    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});

    expect(setImmediate).toHaveBeenCalled();
    expect(setTimeout).not.toHaveBeenCalled();

    clearStack(function() {});
    expect(setImmediate.calls.count()).toEqual(9);
    expect(setTimeout.calls.count()).toEqual(1);

    clearStack(function() {});
    expect(setImmediate.calls.count()).toEqual(10);
    expect(setTimeout.calls.count()).toEqual(1);
  });

  it('uses MessageChannels when available', function() {
    var fakeChannel = {
        port1: {},
        port2: {
          postMessage: function() {
            fakeChannel.port1.onmessage();
          }
        }
      },
      global = {
        MessageChannel: function() {
          return fakeChannel;
        }
      },
      clearStack = jasmineUnderTest.getClearStack(global),
      called = false;

    clearStack(function() {
      called = true;
    });

    expect(called).toBe(true);
  });

  it('uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU', function() {
    var fakeChannel = {
        port1: {},
        port2: {
          postMessage: jasmine
            .createSpy('postMessage')
            .and.callFake(function() {
              fakeChannel.port1.onmessage();
            })
        }
      },
      setTimeout = jasmine.createSpy('setTimeout'),
      global = {
        MessageChannel: function() {
          return fakeChannel;
        },
        setTimeout: setTimeout
      },
      clearStack = jasmineUnderTest.getClearStack(global);

    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});
    clearStack(function() {});

    expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
    expect(setTimeout).not.toHaveBeenCalled();

    clearStack(function() {});
    expect(fakeChannel.port2.postMessage.calls.count()).toEqual(9);
    expect(setTimeout.calls.count()).toEqual(1);

    clearStack(function() {});
    expect(fakeChannel.port2.postMessage.calls.count()).toEqual(10);
    expect(setTimeout.calls.count()).toEqual(1);
  });

  it('calls setTimeout when onmessage is called recursively', function() {
    var fakeChannel = {
        port1: {},
        port2: {
          postMessage: function() {
            fakeChannel.port1.onmessage();
          }
        }
      },
      setTimeout = jasmine.createSpy('setTimeout'),
      global = {
        MessageChannel: function() {
          return fakeChannel;
        },
        setTimeout: setTimeout
      },
      clearStack = jasmineUnderTest.getClearStack(global),
      fn = jasmine.createSpy('second clearStack function');

    clearStack(function() {
      clearStack(fn);
    });

    expect(fn).not.toHaveBeenCalled();
    expect(setTimeout).toHaveBeenCalledWith(fn, 0);
  });

  it('falls back to setTimeout', function() {
    var setTimeout = jasmine.createSpy('setTimeout').and.callFake(function(fn) {
        fn();
      }),
      global = { setTimeout: setTimeout },
      clearStack = jasmineUnderTest.getClearStack(global),
      called = false;

    clearStack(function() {
      called = true;
    });

    expect(called).toBe(true);
    expect(setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 0);
  });
});
